/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.actions;

import robocup.component.ControllerNumbers.PLAY_MODE;
import robocup.component.geometry.Vektor;

/**
 * This is a generic action, which is used by the trainer to set-up 
 * specific situations by placing the players or the ball somewhere on the 
 * field, or to change the play-mode.
 */
public class CoachAction extends Action {

	/**
	 * The play-modes string representation. 
	 */
	private String playMode;

	/**
	 * The tricot number of the player, which should be replaced. 
	 */
	private int playerNumber;

	/**
	 * The teamname of the player, which should be replaced.
	 */
	private String team;

	/**
	 * The x-coordinate of the new players position.
	 */
	private double xPos;

	/**
	 * The y-coordinate of the new players position.
	 */
	private double yPos;

	/**
	 * The players new facing direction.
	 */
	private double facingDir;

	/**
	 * The new x-directed velocity of the player.
	 */
	private double xVel;

	/**
	 * The new y-directed velocity of the player.
	 */
	private double yVel;

	/**
	 * Is eye or ear t set on.
	 */
	private boolean isOn = false;

	/**
	 * <code>CoachAction</code> constructor for MOVE_PLAYER. This is used
	 * to move a player to a certain position with a defined speed and body
	 * direction.
	 * 
	 * @param pNumber
	 *            The player's number.
	 * @param team
	 *            The team name.
	 * @param xPos
	 *            The position's x coordinate.
	 * @param yPos
	 *            The position's y coordinate.
	 * @param facingDir
	 *            The player's facing direction.
	 * @param xVel
	 *            The x-component of the player's velocity.
	 * @param yVel
	 *            The y-component of the player's velocity.
	 */
	public CoachAction(int pNumber, String team, double xPos, double yPos,
			double facingDir, double xVel, double yVel) {
		this._type = TYPE.COACH_MOVE_PLAYER;
		this.playerNumber = pNumber;
		this.team = team;
		Vektor pos = new Vektor(Vektor.XY, xPos, yPos);
		pos.rotate(90);
		this.xPos = pos.x;
		this.yPos = -pos.y;
		pos = new Vektor(Vektor.XY, xVel, yVel);
		pos.rotate(90);
		this.xVel = pos.x;
		this.yVel = -pos.y;
		this.facingDir = facingDir;
	}

	/**
	 * <code>CoachAction</code> constructor for MOVE_BALL, moves the ball to
	 * a certain position with defined speed.
	 * 
	 * @param xPos
	 * @param yPos
	 * @param xVel
	 * @param yVel
	 */
	public CoachAction(double xPos, double yPos, double xVel, double yVel) {
		this._type = TYPE.COACH_MOVE_BALL;
		Vektor pos = new Vektor(Vektor.XY, xPos, yPos);
		pos.rotate(90);
		this.xPos = pos.x;
		this.yPos = -pos.y;
		pos = new Vektor(Vektor.XY, xVel, yVel);
		pos.rotate(90);
		this.xVel = pos.x;
		this.yVel = -pos.y;
	}

	/**
	 * <code>CoachAction</code> constructor, valid types are either 
	 * COACH_RECOVER, COACK_LOOK or COACH_START. Al these have no
	 * further parameters, hence the type defines it exactly.
	 * 
	 * @param type - the action type (Action.TYPE)
	 */
	public CoachAction(TYPE type) {
		switch (type) {
		case COACH_RECOVER: {
			this._type = TYPE.COACH_RECOVER;
			break;
		}
		case COACH_LOOK: {
			this._type = TYPE.COACH_LOOK;
			break;
		}
		default: {
			this._type = TYPE.COACH_START;
			break;
		}
		}
	}

	/**
	 * <code>CoachAction</code> constructor, is used to set the eye or ear on.
	 * Note that this is already done in the initProtocol of the coach/trainer.
	 * 
	 * @param type - either COACH_EYE_ON or COACH_EAR_MODE
	 * @param on - if on == true, then the ear/eye is set on.
	 */
	public CoachAction(TYPE type, boolean on) {
		this.isOn = on;
		switch (type) {
		case COACH_EYE_MODE: {
			this._type = TYPE.COACH_EYE_MODE;
			break;
		}
		default: {
			this._type = TYPE.COACH_EAR_MODE;
			break;
		}
		}
	}

	/**
	 * <code>CoachAction</code> constructor - sets a new play-mode defined
	 * by the given string.
	 * 
	 * @param playMode - the string representation of the playmode in valid
	 * syntax.
	 */
	public CoachAction(String playMode) {
		this._type = TYPE.COACH_PLAY_MODE;
		this.playMode = playMode;
	}

	/**
	 * <code>toString</code>, creates the string representation of this action.
	 * Due to the different types, different actions may result.
	 * 
	 *  <ul>
	 *  	<li>COACH_EYE_MODE : (eye &lt;on|off&gt;)
	 *  	<li>COACH_EAR_MODE : (ear &lt;on|off&gt;)
	 *  	<li>COACH_PLAY_MODE : (change_mode &lt;playMode&gt;)
	 *  	<li>COACH_START : (start)
	 *  	<li>COACH_RECOVER : (recover)
	 *  	<li>COACH_LOOK : (look)
	 *  	<li>COACH_MOVE_BALL : (move (ball) &lt;xPos&gt; &lt;yPos&gt; 0.0 
	 *                              &lt;xVel&gt; &lt;yVel&gt;)
	 *  	<li>COACH_MOVE_PLAYER : (move (player &lt;team&gt; &lt;playerNumber&gt;) 
	 *  							&lt;Pos&gt; &lt;yPos&gt; &lt;facingDir&gt; 
	 *  							&lt;xVel&gt; &lt;yVel&gt;)
	 *  	<li>COACH_KILL_PLAYER : (kill_player  &lt;side&gt; &lt;num&gt;) 
	 *  				!Note! - this command is not understood in the usual 
	 *  				server version. Use the extended version of team dainamite
	 *  				instead!
	 *  </ul>
	 */
	@Override
	public String toString() {
		String cmd = new String();
		switch (this._type) {
		case COACH_EYE_MODE:
			cmd = new String("(eye " + (this.isOn ? "on" : "off") + ")");
			break;
		case COACH_EAR_MODE:
			cmd = new String("(ear " + (this.isOn ? "on" : "off") + ")");
			break;
		case COACH_PLAY_MODE:
			cmd = new String("(change_mode " + this.playMode + ")");
			break;
		case COACH_START:
			cmd = new String("(start)");
			break;
		case COACH_RECOVER:
			cmd = new String("(recover)");
			break;
		case COACH_LOOK:
			cmd = new String("(look)");
			break;
		case COACH_MOVE_BALL:
			cmd = new String("(move (ball) " + this.xPos + " " + this.yPos
					+ " 0.0 " + this.xVel + " " + this.yVel + ")");
			break;
		case COACH_MOVE_PLAYER:
			cmd = new String("(move (player " + this.team + " "
					+ this.playerNumber + ") " + this.xPos + " " + this.yPos
					+ " " + this.facingDir + " " + this.xVel + " " + this.yVel
					+ ")");
			break;
		case COACH_KILL_PLAYER:
			cmd = this.playMode;
		default:
			break;
		}
		return cmd;
	}

	/**
	 * Constant string representation for play-mode: before_kick_off
	 */
	public static final String PLAY_MODE_BEFORE_KICK_OFF = new String(
			"before_kick_off");

	/**
	 * Constant string representation for play-mode: time_over
	 */
	public static final String PLAY_MODE_TIME_OVER = new String("time_over");

	/**
	 * Constant string representation for play-mode: play_on
	 */
	public static final String PLAY_MODE_PLAY_ON = new String("play_on");

	/**
	 * Constant string representation for play-mode: kick_off_left
	 */
	public static final String PLAY_MODE_KICK_OFF_LEFT = new String(
			"kick_off_left");

	/**
	 * Constant string representation for play-mode: kick_off_right
	 */
	public static final String PLAY_MODE_KICK_OFF_RIGHT = new String(
			"kick_off_right");

	/**
	 * Constant string representation for play-mode: kick_in_left
	 */
	public static final String PLAY_MODE_KICK_IN_LEFT = new String(
			"kick_in_left");

	/**
	 * Constant string representation for play-mode: kick_in_right
	 */
	public static final String PLAY_MODE_KICK_IN_RIGHT = new String(
			"kick_in_right");

	/**
	 * Constant string representation for play-mode: free_kick_left
	 */
	public static final String PLAY_MODE_FREE_KICK_LEFT = new String(
			"free_kick_left");

	/**
	 * Constant string representation for play-mode: free_kick_right
	 */
	public static final String PLAY_MODE_FREE_KICK_RIGHT = new String(
			"free_kick_right");

	/**
	 * Constant string representation for play-mode: corner_kick_left
	 */
	public static final String PLAY_MODE_CORNER_KICK_LEFT = new String(
			"corner_kick_left");

	/**
	 * Constant string representation for play-mode: corner_kick_right
	 */
	public static final String PLAY_MODE_CORNER_KICK_RIGHT = new String(
			"corner_kick_right");

	/**
	 * Constant string representation for play-mode: goal_kick_left
	 */
	public static final String PLAY_MODE_GOAL_KICK_LEFT = new String(
			"goal_kick_left");

	/**
	 * Constant string representation for play-mode: goal_kick_right
	 */
	public static final String PLAY_MODE_GOAL_KICK_RIGHT = new String(
			"goal_kick_right");

	/**
	 * Constant string representation for play-mode: goal_left
	 */
	public static final String PLAY_MODE_GOAL_LEFT = new String("goal_left");

	/**
	 * Constant string representation for play-mode: goal_right
	 */
	public static final String PLAY_MODE_GOAL_RIGHT = new String("goal_right");

	/**
	 * Constant string representation for play-mode: penalty_setup_left
	 */
	public static final String PLAY_MODE_PENALTY_SETUP_LEFT = new String(
			"penalty_setup_left");

	/**
	 * Constant string representation for play-mode: penalty_setup_right
	 */
	public static final String PLAY_MODE_PENALTY_SETUP_RIGHT = new String(
			"penalty_setup_right");

	/**
	 * Constant string representation for play-mode: penalty_ready_left
	 */
	public static final String PLAY_MODE_PENALTY_READY_LEFT = new String(
			"penalty_ready_left");

	/**
	 * Constant string representation for play-mode: penalty_ready_right
	 */
	public static final String PLAY_MODE_PENALTY_READY_RIGHT = new String(
			"penalty_ready_right");

	/**
	 * Constant string representation for play-mode: penalty_taken_left
	 */
	public static final String PLAY_MODE_PENALTY_TAKEN_LEFT = new String(
			"penalty_taken_left");

	/**
	 * Constant string representation for play-mode: penalty_taken_right
	 */
	public static final String PLAY_MODE_PENALTY_TAKEN_RIGHT = new String(
			"penalty_taken_right");

	/**
	 * Constant string representation for play-mode: penalty_miss_left
	 */
	public static final String PLAY_MODE_PENALTY_MISS_LEFT = new String(
			"penalty_miss_left");

	/**
	 * Constant string representation for play-mode: penalty_miss_right
	 */
	public static final String PLAY_MODE_PENALTY_MISS_RIGHT = new String(
			"penalty_miss_right");

	/**
	 * Constant string representation for play-mode: penalty_score_left
	 */
	public static final String PLAY_MODE_PENALTY_SCORE_LEFT = new String(
			"penalty_score_left");

	/**
	 * Constant string representation for play-mode: penalty_score_right
	 */
	public static final String PLAY_MODE_PENALTY_SCORE_RIGHT = new String(
			"penalty_score_right");

	/**
	 * <code>getPlayMode</code> - retrieves the play-mode string representation,
	 * given the playmode constant from ControllerNumbers.PLAY_MODE.
	 * 
	 * @param mode - a play-mode enum constant
	 * @return String - the play mode as valid string
	 */
	public static final String getPlayMode(PLAY_MODE mode) {
		switch (mode) {
		case BEFORE_KICK_OFF: {
			return CoachAction.PLAY_MODE_BEFORE_KICK_OFF;
		}
		case CORNER_KICK_OTHER: {
			return CoachAction.PLAY_MODE_BEFORE_KICK_OFF;
		}
		case CORNER_KICK_OWN: {
			return CoachAction.PLAY_MODE_BEFORE_KICK_OFF;
		}
		case FREE_KICK_OTHER: {
			return CoachAction.PLAY_MODE_FREE_KICK_RIGHT;
		}
		case GOAL_KICK_OWN: {
			return CoachAction.PLAY_MODE_FREE_KICK_LEFT;
		}
		case GOAL_OTHER: {
			return CoachAction.PLAY_MODE_GOAL_RIGHT;
		}
		case GOAL_OWN: {
			return CoachAction.PLAY_MODE_GOAL_LEFT;
		}
		case KICK_IN_OTHER: {
			return CoachAction.PLAY_MODE_KICK_IN_RIGHT;
		}
		case KICK_IN_OWN: {
			return CoachAction.PLAY_MODE_KICK_IN_LEFT;
		}
		case KICK_OFF_OTHER: {
			return CoachAction.PLAY_MODE_KICK_OFF_RIGHT;
		}
		case KICK_OFF_OWN: {
			return CoachAction.PLAY_MODE_KICK_OFF_LEFT;
		}
		case PENALTY_MISS_OTHER: {
			return CoachAction.PLAY_MODE_PENALTY_MISS_RIGHT;
		}
		case PENALTY_MISS_OWN: {
			return CoachAction.PLAY_MODE_PENALTY_MISS_LEFT;
		}
		case PENALTY_READY_OTHER: {
			return CoachAction.PLAY_MODE_PENALTY_READY_RIGHT;
		}
		case PENALTY_READY_OWN: {
			return CoachAction.PLAY_MODE_PENALTY_READY_LEFT;
		}
		case PENALTY_SCORE_OTHER: {
			return CoachAction.PLAY_MODE_PENALTY_SCORE_RIGHT;
		}
		case PENALTY_SCORE_OWN: {
			return CoachAction.PLAY_MODE_PENALTY_SCORE_LEFT;
		}
		case PENALTY_SETUP_OTHER: {
			return CoachAction.PLAY_MODE_PENALTY_SETUP_RIGHT;
		}
		case PENALTY_SETUP_OWN: {
			return CoachAction.PLAY_MODE_PENALTY_SETUP_LEFT;
		}
		case PENALTY_TAKEN_OTHER: {
			return CoachAction.PLAY_MODE_PENALTY_TAKEN_RIGHT;
		}
		case PENALTY_TAKEN_OWN: {
			return CoachAction.PLAY_MODE_PENALTY_TAKEN_LEFT;
		}
		case PLAY_ON: {
			return CoachAction.PLAY_MODE_PLAY_ON;
		}
		case TIME_OVER: {
			return CoachAction.PLAY_MODE_TIME_OVER;
		}
		default: {
			return null;
		}
		}
	}

	/**
	 * This method changes the Position of this player/ball, depending on 
	 * the action type.
	 * 
	 * @param x -
	 *            the x position
	 * @param y -
	 *            the y position
	 */
	public void setPosition(double x, double y) {
		this.xPos = x;
		this.yPos = y;
	}

	/**
	 * This method changes the speed of this player/ball, depending on 
	 * the action type.
	 * 
	 * @param x -
	 *            the x velocity
	 * @param y -
	 *            the y velocity
	 */
	public void setSpeed(double d, double e) {
		this.xVel = d;
		this.yVel = e;
	}

	/**
	 * Sets the unum of the player, which should be moved.
	 * 
	 * @param unum - a players tricot number
	 */
	public void setUnum(int unum) {
		this.playerNumber = unum;
	}

	/**
	 * Sets the teamname of a player, which should be moved.
	 * 
	 * @param teamName - the name of the team 
	 */
	public void setTeamName(String teamName) {
		this.team = teamName;
	}

	/**
	 * Returns the actual defined team-name.
	 * 
	 * @return String - the name of the team, from which a player should be 
	 * moved.
	 */
	public String getTeam() {
		return this.team;
	}

	/**
	 * Sets the body direction for a player, which should be moved.
	 * 
	 * @param bodyDir - the new body direction.
	 */
	public void setBodyDir(double bodyDir) {
		this.facingDir = bodyDir;
	}

	/**
	 * Sets the type of the action. Use only 
	 * 	 <ul>
	 *  	<li>COACH_EYE_MODE
	 *  	<li>COACH_EAR_MODE
	 *  	<li>COACH_PLAY_MODE
	 *  	<li>COACH_START
	 *  	<li>COACH_RECOVER
	 *  	<li>COACH_LOOK
	 *  	<li>COACH_MOVE_BALL
	 *  	<li>COACH_MOVE_PLAYER
	 *  	<li>COACH_KILL_PLAYER
	 *  </ul>
	 *  Other s are not defined here. 
	 * @param type - the actions type.
	 */
	public void setType(TYPE type) {
		this._type = type;
	}

	/**
	 * Clones the current action, such that an exact copy is created 
	 * and returned.
	 * 
	 * @param d - an angle, which is added to the facing-direction
	 * @return
	 * 	the new action, which is equal to this one, except the facing
	 *  direction, which could be altered by the parameter
	 */
	public CoachAction cloned(double d) {
		CoachAction action = new CoachAction("");
		action._type = this._type;
		action.playerNumber = this.playerNumber;
		action.team = this.team;

		action.xPos = this.xPos;
		action.yPos = this.yPos;

		action.xVel = this.xVel;
		action.yVel = this.yVel;
		action.facingDir = Vektor.normalize(this.facingDir + d);
		return action;
	}

	/**
	 * This method returns a copy of the position of the command. This is only
	 * defined, if this is a player-move command. The returned position is of
	 * Robocup-Agent WM coordinate space.
	 * 
	 * @return - the position
	 */
	public Vektor getPosition() {
		Vektor pos = new Vektor(Vektor.XY, this.xPos, -this.yPos);
		pos.rotate(-90);
		return pos;
	}

	/**
	 * This method returns a copy of the speed of the command. This is only
	 * defined, if this is a player-move command. The returned speed is of
	 * Robocup-Agent WM coordinate space.
	 * 
	 * @return - the speed
	 */
	public Vektor getSpeed() {
		Vektor spd = new Vektor(Vektor.XY, this.xVel, -this.yVel);
		spd.rotate(-90);
		return spd;
	}

	/**
	 * This method retrieves the uNumber of the player. This is only defined, if
	 * this is a player-move command.
	 * 
	 * @return the unum
	 */
	public int getNumber() {
		return this.playerNumber;
	}
}
